﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace PlottingBasics.LINQHelpers
{
    /// <summary>
    /// Helper class for enumerators that will get the two items that are either side of a value.
    /// </summary>
    public static class Adjacent
    {
        public static Pair<TSource, TSource> AdjacentItems<TSource, TKey>(this IEnumerable<TSource> source, TKey val,
            Func<TSource, TKey> keySelector, IComparer<TKey> doTest)
        {
            var sorted = source.OrderBy(keySelector);
            TSource first = default(TSource);
            TSource second = default(TSource);
            foreach (var p in sorted)
            {
                first = second;
                second = p;

                ///
                /// Have we hit the end here?
                /// 

                TKey pKey = keySelector(p);
                int cmp = doTest.Compare(val, pKey);
                if (cmp == 0)
                {
                    return new Pair<TSource, TSource>(p, p);
                }

                if ( cmp < 0)
                {
                    return new Pair<TSource, TSource>(first, second);
                }
            }

            ///
            /// If we got here, then we fell off the end which means
            /// val was greater than everything
            /// 

            return new Pair<TSource, TSource>(second, default(TSource));
        }

        /// <summary>
        /// Find the two items that are adjacent in ordering to a value.
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TKey"></typeparam>
        /// <param name="source"></param>
        /// <param name="val"></param>
        /// <param name="keySelector"></param>
        /// <returns></returns>
        public static Pair<TSource, TSource> AdjacentItems<TSource, TKey>(this IEnumerable<TSource> source, TKey val, Func<TSource, TKey> keySelector)
            where TKey : IComparable<TKey>
        {
            return source.AdjacentItems(val, keySelector, Comparer<TKey>.Default);
        }

        /// <summary>
        /// Find the two items that are adjacent in ordering to a value.
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <param name="val"></param>
        /// <returns></returns>
        public static Pair<TSource, TSource> AdjacentItems<TSource>(this IEnumerable<TSource> source, TSource val)
            where TSource : IComparable<TSource>
        {
            return source.AdjacentItems<TSource, TSource>(val, a => a);
        }

        /// <summary>
        /// Find the two items that are adjacent in ordering to a value.
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <param name="val"></param>
        /// <param name="doComp"></param>
        /// <returns></returns>
        public static Pair<TSource, TSource> AdjacentItems<TSource>(this IEnumerable<TSource> source, TSource val, IComparer<TSource> doComp)
        {
            return source.AdjacentItems<TSource, TSource>(val, a => a, doComp);
        }
    }
}
